
import socket
import os
import random
pwd = os.path.realpath(__file__)
pwd = pwd[:pwd.rfind("/")]
class FtpController:
    __mode = 'sim'
    __config_file_path  = ""
    __config_space = {
        'anonymous_enable':['YES', 'NO'],
        'anon_upload_enable':['YES', 'NO'],
        'no_anon_password':['YES', 'NO'],
        'banner_file':['/etc/vsftpd_banner0','/etc/vsftpd_banner1','/etc/vsftpd_banner2','/etc/vsftpd_banner3',],
        'chroot_local_user': ['YES', 'NO'],
        'anon_root':    ['/srv/ftp0', '/srv/ftp1', '/srv/ftp2', '/srv/ftp3'],
        'anon_other_write_enable':['YES', 'NO'],
        'anon_mkdir_write_enable':['YES', 'NO'],
        'ftp_username': ['ftp'],
        'listen_port': ['21']
    }
    __cur_configs = None
    __cur_ip = "192.168.22.128"
    __default_features = '''
listen=YES
listen_ipv6=NO
userlist_deny=NO
userlist_enable=YES
userlist_file=/etc/allowed_users
local_root=/srv/ftp0
pasv_promiscuous=yes
pasv_enable=YES
#port_enable=yes
#connect_from_port_20=yes
pasv_min_port=8000         
pasv_max_port=8100 
# Allow anonymous FTP? (Disabled by default).
anon_umask=000
# log
xferlog_enable=YES
log_ftp_protocol=YES
# Uncomment this to allow local users to log in.
local_enable=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES
dirmessage_enable=YES
#
# If enabled, vsftpd will display directory listings with the time
# in  your  local  time  zone.  The default is to display GMT. The
#
chroot_list_enable=NO
allow_writeable_chroot=YES
    '''
    def __init__(self,mode='sim',config_file_path = '/etc/vsftpd.conf'):
        
        self.__mode = mode
        self.__config_file_path = config_file_path
        self.__cur_ip = "192.168.22.128"
        self.__cur_configs = {
        'anonymous_enable':'YES',
        'anon_upload_enable':'YES',
        'no_anon_password':'YES',
        'banner_file':'/etc/vsftpd_banner0',
        'chroot_local_user': 'YES',
        'anon_root':    '/srv/ftp0',
        'anon_other_write_enable':'YES',
        'anon_mkdir_write_enable':'YES',
        'ftp_username': 'ftp',
        'listen_port': '21',
    }
        # initalize configs
        if self.__mode == 'real':
            config_file = open(self.__config_file_path,'r')
            config_buffer = config_file.read()
            configs = {}
            for each_config in self.__config_space:
                configs[each_config] = self.__get_config_value(config_buffer,each_config)
            config_file.close()
            # initialize ip
            hostname = socket.gethostname()
            os.system(pwd + "/get_ip.sh")

            self.__cur_ip = self.get_ip_address()
            self.__cur_configs = configs
            config_file.close()

    def __get_config_value(self,buff,config_name):
         name_index = buff.find(config_name)
         value_start = len(config_name) +1
         end_index = buff[name_index:].find("\n")
         return buff[name_index + value_start:name_index + end_index]
    
    def get_ip_address(self):
        file = open(pwd + "/ip_address.txt")
        ip = file.read()
        return ip[:-1]

    @property
    def config_spaces(self):
        return self.__config_space
    @property
    def mode(self):
        return self.__mode
    @property
    def cur_configs(self):
        return self.__cur_configs
    @property
    def num_of_configs(self):
        return len(self.__config_space)
    @property
    def ip(self):
        return self.__cur_ip
    @property
    def pkts(self):
        os.system( pwd + "/hist_pkts.sh")
        pkt_file = open(pwd + "/current_pkts.txt")
        pkt_num = int(pkt_file.read())
        pkt_file.close()
        return pkt_num
    @staticmethod
    def get_config_space(config_name):
        return FtpController.__config_space[config_name]

    def get_configs(self):
        return self.__cur_configs
        
    def set_configs(self,configs):
        self.__cur_configs = configs
        if self.__mode == 'sim': return 
        # mode == 'real'
        config_file = open(self.__config_file_path,'w')
        configs = self.__default_features + '\n'
        for each_config in self.__config_space:
            configs += (each_config + "=" + self.__cur_configs[each_config]  + '\n')
        config_file.write(configs)
        config_file.close()

    def change_ip(self,ip):
        self.__cur_ip = ip
        ip_shell_path = pwd + "/change_ip.sh"
        if self.__mode == 'real':
            os.system(ip_shell_path + " " +ip)

    def restart_vsftpd(self):
        if self.__mode == 'real':
            os.system('service vsftpd restart')
    def start_vsftpd(self):
        if self.__mode == 'real':
            os.system('service vsftpd start')
    def random_change(self,exceptions = None):
        for each_config in self.__cur_configs:
            config_value = self.__cur_configs[each_config]
            if config_value in exceptions:
                continue
            value_space = self.__config_space[each_config]
            space_len = len(value_space)
            value_index = random.randint(0,space_len-1)
            value = value_space[value_index]
            if value == self.__cur_configs[each_config]:
                value_index = (value_index +1) % space_len
                value  = value_space[value_index]
            self.__cur_configs[each_config] = value
        
        self.__cur_ip = '192.168.' + str(net_zone) + '.' + str(random.randint(140,160))
        self.change_ip(self.__cur_ip)
        # print('current ip:',self.__cur_ip)
        # for each_key in self.__cur_configs:
        #     print(each_key + ":" + self.__cur_configs[each_key])
        # print('current configs:',self.__cur_configs)
        self.set_configs(self.__cur_configs)
        self.restart_vsftpd()